package com.atcentaline.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

/**
 * 描述：面向切面编程，定义一个切面。
 * 1、定义切面，说白了就是一个类
 * 2、在这个类上加上两个注解@Aspect、@Component
 *
 * @author: wbzhangzp
 * @date: 2021-05-13 20:22
 */
@Aspect
@Component
public class LogAop {

    // 寻找规则
    // 切点
    // @Pointcut("execution(* com.atcentaline.service..*(..))") 扫描该路径下的类就会生效
    @Pointcut("@annotation(LogAnnotation)") // 要通过切面控制的方法，方法要使用注解才会生效
    public void pointCut() {

    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("----before----执行到了LogAop......");
        // 目标对象
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("className = " + className);
        System.out.println("methodName = " + methodName);

        // 方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 取参数
        String[] parameterNames = methodSignature.getParameterNames();
        // 参数值
        Object[] args = joinPoint.getArgs();
        System.out.println("打印参数开始。。。。。。");
        for (int i = 0; i < parameterNames.length; i++) {
            System.out.println(parameterNames[i] + " = " + args[i]);
        }
        System.out.println("打印参数结束。。。。。。");
    }

    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        System.out.println("---after---执行到了LogAop");
    }

    // 注意：returning的值要与方法的形参一致
//    @AfterReturning(pointcut = "pointCut()", returning = "rs")
//    public void afterR(Object rs) {
//        System.out.println("---afterR---执行到了LogAop");
//        System.out.println(rs);
//    }

    @AfterReturning(pointcut = "pointCut()", returning = "rs")
    public Object afterR(Object rs) {
        System.out.println("---afterR---执行到了LogAop");
        System.out.println("afterR拦截到的结果==" +rs);

        return rs;
    }

    @AfterThrowing(pointcut = "pointCut()", throwing = "throwable")
    public void afterThrow(Throwable throwable) {
        System.out.println("----AfterThrowing 统一错误处理----");
        System.out.println("错误信息：==》" + throwable.getMessage());
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("----Around--Starter----执行到了LogAop");
        System.out.println("Around内部接收的相关数据");
        // 目标对象
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("className = " + className);
        System.out.println("methodName = " + methodName);

        // 获取目标对象执行的方法里面的参数
        // 1、方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 2、取参数
        String[] parameterNames = methodSignature.getParameterNames();
        // 3、打印参数值
        Object[] args = joinPoint.getArgs();
        System.out.println("打印参数开始。。。。。。");
        for (int i = 0; i < parameterNames.length; i++) {
            System.out.println(parameterNames[i] + " = " + args[i]);
        }
        System.out.println("打印参数结束。。。。。。");

        // 修改参数
        // Object[] newArgs = {99,"王五"};

        // 接收注解的参数
        LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class);
        // 输出
        String value = logAnnotation.value();
        String des = logAnnotation.description();
        boolean flag = logAnnotation.flag();

        System.out.println("value = " + value);
        System.out.println("des = " + des);
        System.out.println("flag = " + flag);

        // 手动去执行真正的业务方法
        Object result = joinPoint.proceed();

        System.out.println("----Around--End----执行到了LogAop");

        return result;
    }

}
